﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CommunityToolkitMvvmDemo.UserControls
{
    /// <summary>
    /// Instrument.xaml 的交互逻辑
    /// </summary>
    public partial class Instrument : UserControl
    {
        public Instrument()
        {
            InitializeComponent();

            this.SizeChanged += Instrument_SizeChanged;

             this.Loaded += Instrument_Loaded;
        }
        private void Instrument_Loaded(object sender, RoutedEventArgs e)
        {
            Refresh();
        }

        private void Instrument_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            double minSize = Math.Min(this.RenderSize.Width, this.RenderSize.Height);
            this.backEllipse.Width = minSize;
            this.backEllipse.Height = minSize;
        }

        #region 依赖属性
        /// <summary>
        /// 依赖属性 - 设置背景颜色
        /// </summary>
        public Brush SetBackground
        {
            get { return (Brush)GetValue(SetBackgroundProperty); }
            set { SetValue(SetBackgroundProperty, value); }
        }
        public static readonly DependencyProperty SetBackgroundProperty =
            DependencyProperty.Register("SetBackground", typeof(Brush), typeof(Instrument), 
                new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 字体大小
        /// </summary>
        public int ScaleTextSize
        {
            get { return (int)GetValue(ScaleTextSizeProperty); }
            set { SetValue(ScaleTextSizeProperty, value); }
        }
        public static readonly DependencyProperty ScaleTextSizeProperty =
            DependencyProperty.Register("ScaleTextSize", typeof(int), typeof(Instrument), 
                new PropertyMetadata(12, new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 画刷颜色
        /// </summary>
        public Brush ScaleBrush
        {
            get { return (Brush)GetValue(ScaleBrushProperty); }
            set { SetValue(ScaleBrushProperty, value); }
        }
        public static readonly DependencyProperty ScaleBrushProperty =
            DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Instrument), 
                new PropertyMetadata(default(Brush), new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 最小值
        /// </summary>
        public int MinValue
        {
            get { return (int)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(int), typeof(Instrument), 
                new PropertyMetadata(0, new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 最大值
        /// </summary>
        public int MaxValue
        {
            get { return (int)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(int), typeof(Instrument), 
                new PropertyMetadata(100, new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 当前值
        /// </summary>
        public int CurrentValue
        {
            get { return (int)GetValue(CurrentValueProperty); }
            set { SetValue(CurrentValueProperty, value); }
        }
        // 依赖属性 ValuealueProperty
        public static readonly DependencyProperty CurrentValueProperty =
            DependencyProperty.Register("CurrentValue",
                typeof(int),
                typeof(Instrument),
                new PropertyMetadata(0 ,new PropertyChangedCallback(OnPropertyChanged)));

        /// <summary>
        /// 依赖属性 - 大刻度线间隔数
        ///  MinValue="20"  MaxValue="100"  Interval="4" 
        ///  MinValue="10"  MaxValue="100"  Interval="9" 
        ///  MinValue="5"  MaxValue="100"  Interval="19" 
        ///  MinValue="5"  MaxValue="50"  Interval="9" 
        /// </summary>
        public int Interval
        {
            get { return (int)GetValue(IntervalProperty); }
            set { SetValue(IntervalProperty, value); }
        }
        public static readonly DependencyProperty IntervalProperty =
            DependencyProperty.Register("Interval", typeof(int), typeof(Instrument),
                new PropertyMetadata(10, new PropertyChangedCallback(OnPropertyChanged)));

        #endregion

        /// <summary>
        /// 当值发生变化时，执行 OnPropertyChanged 方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        public static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Instrument).Refresh();// 在静态方法中，执行实例方法
        }

        /// <summary>
        /// 实例方法
        /// </summary>
        private void Refresh()
        {
            double radius = this.backEllipse.Width / 2;
            this.mainCanvas .Children.Clear();

            // 将270°在 最大值和最小值之间 均分出的角度，用于小刻度
            double step = 270.0/(this.MaxValue-this.MinValue);

            // 小刻度线
            /*
               角度定义：两条射线从圆心向圆周射出，形成一个夹角和夹角正对的一段弧。当弧长正好等于圆周长的360分之一时，两条射线的夹角的大小为1度。(单位: º）
               弧度定义：两条射线从圆心向圆周射出，形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时，两条射线的夹角大小为1弧度（单位：rad)

             弧度 = 角度*PI/180 
             角度 = 弧度 * 180 / PI
             弧度 = 2*PI/360*角度

             假设一个圆的圆心坐标是(a, b)，半径为r则圆上每个点的：
                X坐标=a + Math.sin(角度 * (Math.PI / 180)) * r ；
                Y坐标=b + Math.cos(角度 * (Math.PI / 180)) * r ； 

             以“12点为起点, 角度增大时为顺时针方向“，求X坐标和Y坐标的方法是：
                X坐标=a + Math.sin(角度 * (Math.PI / 180)) * r ；
                Y坐标=b - Math.cos(角度 * (Math.PI / 180)) * r ；

             一般“3点为起点, 角度增大时为逆时针方向“，求X坐标和Y坐标的方法是：
                X坐标 = a + Math.cos(角度 * (Math.PI / 180)) * r;    
                Y坐标 = b - Math.sin(角度 * (Math.PI / 180)) * r; 
            */

            for (int i = 0; i < this.MaxValue - this.MinValue; i++)
            {
                Line lineScale = new Line();
                lineScale.Stroke = this.ScaleBrush;
                lineScale.StrokeThickness = 1;

                // 角度-45 ，将缺口向下
                // X1 Y1 靠近圆心的点， X2 Y2 靠近圆周的点
                lineScale.X1 = radius- (radius - 13) * Math.Cos((i * step - 45) * Math.PI / 180);
                lineScale.Y1 = radius- (radius - 13) * Math.Sin((i * step - 45) * Math.PI / 180);

                lineScale.X2 = radius - (radius - 8) * Math.Cos((i * step - 45) * Math.PI / 180);
                lineScale.Y2 = radius - (radius - 8) * Math.Sin((i * step - 45) * Math.PI / 180);
                // 画小刻度线
                this.mainCanvas.Children.Add(lineScale);
            }

            // 将270° 均分出的角度，用于大刻度
            step = 270.0 / this.Interval;

            // 第一个大刻度值
            int scaleText = (int)this.MinValue; 

            // 大刻度线
            for (int i = 0; i <= this.Interval; i++)
            {
                Line lineScale = new Line();
                lineScale.Stroke = this.ScaleBrush;
                lineScale.StrokeThickness = 1;

                lineScale.X1 = (radius - (radius - 20) * Math.Cos((i * step - 45) * Math.PI / 180));
                lineScale.Y1 = radius - (radius - 20) * Math.Sin((i * step - 45) * Math.PI / 180);

                lineScale.X2 = radius - (radius - 8) * Math.Cos((i * step - 45) * Math.PI / 180);
                lineScale.Y2 = radius - (radius - 8) * Math.Sin((i * step - 45) * Math.PI / 180);
                // 画大刻度线
                this.mainCanvas.Children.Add(lineScale);

                // 大刻度文字
                TextBlock textScale = new TextBlock();
                textScale.Foreground =this.ScaleBrush;
                textScale.Width = 34;
                textScale.FontSize = this.ScaleTextSize;
                textScale.TextAlignment = TextAlignment.Center;
                //textScale.Background = Brushes.Red; // 用于调试 显示的位置

                textScale.Text = (scaleText +( (this.MaxValue - this.MinValue) / Interval ) * i).ToString();

                // -17 ，宽度的一半
                Canvas.SetLeft(textScale,radius - (radius - 36) * Math.Cos((i * step - 45) * Math.PI / 180)-17);
                Canvas.SetTop(textScale,radius - (radius - 36) * Math.Sin((i * step - 45) * Math.PI / 180)-10);

                this.mainCanvas.Children.Add(textScale);
            }

            // 装饰圆弧
            //string sData = "M100 200 A100 100 0 1 1 200 300";
            string sData = "M{0}  {1}  A{0}  {0}  0  1  1  {1}  {2}";
            sData = string.Format(sData, radius / 2, radius, radius * 1.5);
            var converter = TypeDescriptor.GetConverter(typeof(Geometry));
            //this.circle.Stroke = this.ScaleBrush;
            this.circle.Data = (Geometry)converter.ConvertFrom(sData);

            // 指针指向 ，指针即三角形
            // 指针初始的角度：水平指向左边，后面需要角度需要 -45
            sData = "M{0}  {1} ,{1}  {2}, {1}  {3}";
            sData = string.Format(sData, radius*0.3, radius, radius -5, radius+5);
            this.pointer.Data = (Geometry)converter.ConvertFrom(sData);
            this.pointer.Fill = this.ScaleBrush;
            this.pointer.Stroke = this.ScaleBrush;

            // 指针动画
            step = 270.0 / (this.MaxValue - this.MinValue);
            // 指针指向 - 无动画
            //this.rtPointer.Angle = (this.CurrentValue - this.MinValue) * step - 45;

            // 指针指向 - 动画
            DoubleAnimation da = new DoubleAnimation((int)((this.CurrentValue - this.MinValue) * step - 45), 
                new Duration(TimeSpan.FromMilliseconds(200)));
            this.rtPointer.BeginAnimation(RotateTransform.AngleProperty, da);
        }
    }
}
